import { getQualifiedClassName } from "../Utility/dx/getQualifiedClassName";
import { ResouceManager } from "../Managers/ResouceManager";
import { DelayFramer } from "../Ticks/DelayFramer";
import { Loader } from "../Loader/Loader";
import { Assets } from "../Support/Assets";
import { IModule } from "../Interfaces/IModule";
import { Fun } from "../Utility/dx/Fun";
import { IDispose } from "../Interfaces/IDispose";
import { EventManager } from "../Managers/EventManager";
import { ModuleEvent } from "../Event/ModuleEvent";
import { Application } from "./Application";
import { getNodePath } from "../Utility/dx/getNodePath";
import { currentSceneNode } from "../Utility/dx/currentSceneNode";
import { ModuleNames } from "../Enums/ModuleNames";

/**
 * 如果模块中需要加载Prefab，需要重写assets
 * protected get assets():string[]
 * {
 *      return [];
 * }
 */

export class FModule implements IModule {
    public moduleName: string = null;
    /**是否需要对素材进行预加载 */
    public isNeedPreload: boolean = false;
    /**是否需要对素材进行缓存 */
    public isNeedCache: boolean = true;
    /**需要播放完动画才销毁 */
    public isPlayDisposeAnimation: boolean = true;
    /**是否需要显示加载进度条 */
    public isNeedShowLoadBar: boolean = false;
    private nodePath: string;
    protected node: cc.Node;
    protected parent: cc.Node;
    protected moduleData: any = null;

    protected isInitAsset: boolean = false;// 模块中的素材是否已经初始完成，包括加载完成
    protected _isInitialize: boolean = false;// 模块是否初始化

    private isShowModule: boolean = false;// 模块是否被显示
    private delayCalls: any[] = [];

    protected disObjects: IDispose[] = [];

    public constructor() { this.moduleName = getQualifiedClassName(this); }
    public get assets(): any[] { return []; }
    public get isInitialize(): boolean { return this._isInitialize; }


    public startModule(): void {
        if (this._isInitialize) return;
        this.initialize();
    }
    protected initialize(): void {
        this._isInitialize = true;
        this.loadAssets();
    }
    protected loadAssets(): void {
        if (this.assets.length == 0) this.initViews();
        else {
            let loader: Loader = Loader.Get();
            loader.cacheAsset = this.isNeedCache;
            loader.addCallback(null, () => this.initViews(), (p) => this.onLoadAssetProgress(p));
            loader.loads(Assets.GetAssets(this.assets));
        }
    }
    private onLoadAssetProgress(p: number): void {
        if (this.isNeedPreload) return;
        if (this.isNeedShowLoadBar) {
            // console.log(this.moduleName,this.isNeedPreload,this.isNeedShowLoadBar,"------>",p);
            // EventManager.dispatchModuleEventWith(ModuleEvent.LOAD_MODULE_ASSET_PROGRESS + this.moduleName, this.moduleName, null, { progress: p });
            // EventManager.dispatchModuleEventWith(ModuleEvent.LOAD_MODULE_ASSET_PROGRESS, this.moduleName, null, { progress: p });
        }
    }
    protected initViews(): void {
        if (this.isInitAsset) return;

        EventManager.dispatchModuleEventWith(ModuleEvent.LOAD_MODULE_ASSET_COMPLETE + this.moduleName, this.moduleName);
        EventManager.dispatchModuleEventWith(ModuleEvent.LOAD_MODULE_ASSET_COMPLETE, this.moduleName);

        if (this.node == null)
            this.node = this.createMainNode();
        this.createViews();
        if (this.isShowModule)
            this.showViews();
        DelayFramer.Push(Fun(this.excuteDelayCalls, this));
        this.addEvents();
        this.isInitAsset = true;
        //console.log("==================",this.moduleName,this.isInitAsset);
    }
    /**创建主节点 */
    protected createMainNode(): cc.Node {
        if (this.assets.length > 0) return this.instantiatePrefab(this.assets[0]);
        return new cc.Node(this.moduleName);
    }
    protected createViews(): void {

    }
    protected showViews(): void {
        if (this.node != null) {
            this.node.name = this.moduleName;
            if (!this.node.parent && this.parent) {
                this.parent.addChild(this.node);
                if (this.moduleName != ModuleNames.Mask && this.moduleName != ModuleNames.Preload) {
                    TweenLite.killTweensOf(this.node);
                    TweenLite.fromTo(this.node, .2, { scale: 0 }, { scale: 1 });
                }
            }

            if (this.moduleData != null) {
                if (this.moduleData["x"] != undefined) this.node.x = this.moduleData["x"];
                if (this.moduleData["y"] != undefined) this.node.y = this.moduleData["y"];
                if (this.moduleData['rejectOther'] != undefined) currentSceneNode().on(cc.Node.EventType.TOUCH_END, this.onRejectOther, this, true);
            }
        }
    }
    private onRejectOther(evt: cc.Event.EventTouch) {
        let targetPath = getNodePath(evt.target);
        let rejectCallback = this.moduleData['rejectCallback'];
        if (!this.nodePath) this.nodePath = getNodePath(this.node);
        if (targetPath.indexOf(this.nodePath) != 0) {
            Application.CurrentScene.node.off(cc.Node.EventType.TOUCH_END, this.onRejectOther, this, true);
            if (rejectCallback != null) rejectCallback.call(this, evt);
            else this.hide();
        }
    }
    public show(p: cc.Node, data?: object): void {
        this.isShowModule = true;
        this.moduleData = data;
        this.parent = p;
        if (this.parent != p && this.node != null)
            this.node.removeFromParent();
        if (this.isInitAsset)
            this.showViews();
    }
    public hide(data?: object): void 
    {        
        this.isShowModule = false;
        if (this.node != null)
            if (this.moduleName != ModuleNames.Mask) {
                TweenLite.to(this.node, .2, { scale: 0,onComplete: () => { this.node.removeFromParent() } });
            }
            else
                this.node.removeFromParent();
    }
    /**添加事件 */
    protected addEvents(): void {
    }
    protected removeEvents(): void {
        EventManager.removeEvent(this);
    }

    protected onHideAnimationComplete(): any {
        this.isPlayDisposeAnimation = false;
        this.dispose();
    }
    public dispose(): void {
        if (this.isPlayDisposeAnimation && this.node && this.node.isValid) {
            this.hide();
            if (this.node.parent) {
                let t: any[] = TweenLite.getTweensOf(this.node, true);
                if (t.length > 0)
                    t[0].vars.onComplete = () => this.onHideAnimationComplete();
                return;// 如果Hide方法里面没有动效直接销毁模块
            }
        }
        this.removeEvents();
        this.disposeObjects();
        if (this.node && this.node.isValid) {
            TweenLite.killTweensOf(this.node);
            this.node.destroy();
        }
        if (this.moduleData && this.moduleData['rejectOther'] != undefined) currentSceneNode().off(cc.Node.EventType.TOUCH_END, this.onRejectOther, this, true);
        console.log(this.moduleName, "==> 销毁完成！！！");
        if(this.node){
            TweenLite.killTweensOf(this.node);
        }
        this.isShowModule = false;
        this.isInitAsset = false;
        this._isInitialize = false;
        this.delayCalls.length = 0;
        this.parent = null;
        this.moduleData = null;
        this.moduleName = null;
        this.node = null;
    }

    protected addObject(obj: IDispose): void {
        if (this.disObjects.indexOf(obj) == -1)
            this.disObjects.push(obj);
    }
    protected disposeObjects(): void {
        while (this.disObjects.length > 0) {
            this.disObjects.shift().dispose();
        }
    }

    /**实例化预制体 */
    protected instantiatePrefab(prefabName: string): any { return ResouceManager.InstantiatePrefab(prefabName); }
    /**调用模块的方法，如果模块没有被初始化跟素材还没初始化完成，则会延时到素材初始化完成后调用模块的方法 */
    public excuteModuleFun(funName: string, ...args): void {
        if (!this.isInitAsset || this.delayCalls.length > 0) this.delayCalls.push({ funName: funName, args: args });
        else {
            let fun: Function = this[funName];
            if (fun != null) fun.apply(this, args);
        }
    }
    private excuteDelayCalls(): void {
        if (!this.isInitAsset) return;
        while (this.delayCalls.length > 0) {
            let o = this.delayCalls.shift();
            let fun: Function = this[o.funName];
            if (fun != null) fun.apply(this, o.args);
        }
    }
}
